using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Tracking;
using System.Workflow.ComponentModel.Compiler;
using System.Xml;
using System.IO;
using OpenComposite.EII.Designer.Workflow;
using System.Workflow.ComponentModel;
using System.Workflow.Activities;
using System.Security.Policy;
using System.Reflection;
using System.Threading;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.ComponentModel.Design;
using OpenComposite.EII.Repository;
using Aga.Controls.Tree.NodeControls;
using Aga.Controls.Tree;
using OpenComposite.Repository.Properties;
using System.Collections.ObjectModel;
using OpenComposite.Base.Collections;
using WeifenLuo.WinFormsUI.Docking;
using System.Runtime.Serialization.Formatters.Binary;
using System.Globalization;
using Microsoft.Reporting.WinForms;
using System.Linq;
using OpenComposite.Workflow;

namespace OpenComposite.EII.Simulation
{
	public partial class FormWorkflowSimulation : DockContent
	{
		#region Initialization
		public FormWorkflowSimulation(WorkflowController wfController)
		{
			_wfController = wfController;

			InitializeComponent();

			this.TabText = this.Text = wfController.Workflow.Name + " Simulation";

			txtWFName.Text = wfController.Workflow.Name;
			tslblProcessName.Text = wfController.Workflow.Name;

			init();
		}
		private void init()
		{
			dcSVDistribution.DataType = typeof(string);
			// databind dtSimVars to dgvSimVars
			dgvSimVars.AutoGenerateColumns = false;
			dgvSimVars.DataSource = dtSimVars;
			// init simulation variables datatable
			//foreach ( BusinessObjectField field in _wfController.Workflow.Capability.InputBusinessObject.BusinessObjectFields ) {
			//    dtSimVars.Rows.Add(field.Name, field.DataType, "", "", "");
			//}
			foreach ( OpenComposite.EII.Repository.Workflow.RuleParameterResolve rpr in _wfController.Workflow.ExtendedProperties.WorkflowVariables ) {
				dtSimVars.Rows.Add(rpr.ParameterName, rpr.ParameterDataType, "", "", "", "None");
			}
			businessObjectTreeView1.WorkflowController = _wfController;
			if ( _wfController.Workflow.Capability != null ) {
				businessObjectTreeView1.BusinessObject = _wfController.Workflow.Capability.InputBusinessObject;
			} else {
				businessObjectTreeView1.BusinessObject = _wfController.Workflow.InputBusinessObject;
			}
			businessObjectTreeView1.Load();

		}
		#endregion

		#region Protected Members

		#region Methods
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
		protected override void Dispose(bool disposing)
		{
			try {
				stopWF();
			} catch {
			}
			if ( disposing && ( components != null ) ) {
				components.Dispose();
			}
			base.Dispose(disposing);
		}
		protected override void OnActivated(EventArgs e)
		{
			base.OnActivated(e);
			RepositorySurfaceManager rsm = _wfController.GetService(typeof(RepositorySurfaceManager)) as RepositorySurfaceManager;
			if ( rsm != null ) {
				rsm.ActiveDesignSurface = null;
			}
		}
		#endregion

		#endregion

		#region Private Members

		#region Constants
		private const string _PROCESS = "Process";
		private const string _DISTRIBUTION = "Distribution";
		#endregion

		#region Variables
		private BindingListEx<DocumentTrackingValue> _trackedDocuments = new BindingListEx<DocumentTrackingValue>();
		private WorkflowRuntime _runtime;
		private SimulationTrackingService _trackingsvc;
		private WorkflowController _wfController;
		private NodeControlInfo _selectedNode = NodeControlInfo.Empty;

		//private bool _customSimCyclesCount = false;
		private bool _isExiting = false;
		private int _completedCount;
		private Random _random = new Random();
		private DateTime _dtStart;

		List<Guid> _lstInstances;
		List<string> _lstActNames;

		private volatile WorkflowCompilerResults _currentCompileResults;

		private object lockThis = new object();
		#endregion

		#region Methods

		private void beginSimulation(bool forceCompile)
		{
			_dtStart = DateTime.Now;
			_lstInstances = new List<Guid>();
			_lstActNames = new List<string>();
			_waitHandle = new AutoResetEvent(false);
			_trackedDocuments = new BindingListEx<DocumentTrackingValue>();

			if ( startWF(forceCompile) ) {
				setButtons(true);
			} else {
				if ( _isExiting ) return;
				endSimulation();
				setButtons(false);
				tslblStatus.Text = "Simulation Failed.";
			}
		}
		private void endSimulation()
		{
			this.SuspendLayout();
			try {
				TimeSpan timeSim = DateTime.Now - _dtStart;
				setButtons(false);
				tsbtnContinue.Enabled = false;
				tsbtnContinue.Visible = false;
				dgvTracking.DataSource = dsTracking.Tables[0];
				//stopWF();
				tslblStatus.Text = "Simulation Completed.";// Duration=" + timeSim.ToString();
				if ( rbnProcess.Checked ) {
					showResults(null);
					calculateSummary();
					tabControl1.SelectedTab = tabResults;
				} else if ( rbnDocuments.Checked ) {
					tabControl1.SelectedTab = tabDetails;
				}
				this.Cursor = Cursors.Default;
				//MessageBox.Show("Simulation Completed.", "Simulation", MessageBoxButtons.OK, MessageBoxIcon.Information);
				string kpinm = cmbKPI.SelectedValue as string;

				splitContainerKPIOrDocuments.Panel1Collapsed = !rbnProcess.Checked;
				splitContainerKPIOrDocuments.Panel2Collapsed = !rbnDocuments.Checked;

				if ( rbnProcess.Checked ) {
					if ( !string.IsNullOrEmpty(kpinm) ) {
						showResults(kpinm);
					}
				} else if ( rbnDocuments.Checked ) {
					showTrackedDocuments();
					if ( tvAdvTrackedDocumentCapabilities.Root.Children.Count > 0 ) {
						tvAdvTrackedDocumentCapabilities.SelectedNode = tvAdvTrackedDocumentCapabilities.Root.Children[0];
					}
				}
				tsprogressSim.Visible = false;
			} finally {
				bgworkerSimStart.CancelAsync();
				this.ResumeLayout(true);
			}
		}

		private bool startWF(bool forceCompile)
		{
			dgvResults.DataSource = null;
			dgvTracking.DataSource = null;

			// init variables
			dsTracking.Clear();
			_completedCount = 0;
			dtResults.Clear();
			if ( rbnProcess.Checked ) {
				calculateSimCycles();
				if ( dtSimCycles.Rows.Count == 0 ) {
					MessageBox.Show("No simulation values available.", "Start Simulation", MessageBoxButtons.OK, MessageBoxIcon.Warning);
					return false;
				}
				// init dsResults: add KPI columns
				BindingListEx<KeyPerformanceIndicator> kpis = Global.Data.GetKeyPerformanceIndicatiors();
				while ( dtResults.Columns.Count > 2 ) dtResults.Columns.RemoveAt(2);
				foreach ( KeyPerformanceIndicator kpi in kpis ) {
					DataColumn col = dtResults.Columns.Add(kpi.Name,
						Helpers.GetDotNetTypeOfDataTypeString(kpi.DataType));
					if ( kpi.ExtendedProperties.Units.Count > 0 ) {
						dtResults.Columns.Add(kpi.Name + "_Unit", typeof(string));
					}
				}
			}
			try {
				Application.DoEvents();
				AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

				// init progress bar
				tsprogressSim.Value = 0;
				if ( rbnDocuments.Checked ) {
					tsprogressSim.Maximum = 8; // + 6 => starting, compiled, wfruntime started,...
				} else {
					tsprogressSim.Maximum = dtSimCycles.Rows.Count * 2 + 7; // + 6 => starting, compiled, wfruntime started,...
				}
				tsprogressSim.Visible = true;

				if ( forceCompile || _currentCompileResults == null || _currentCompileResults.CompiledAssembly == null ) {
					bgworkerSimStart = new BackgroundWorker();
					bgworkerSimStart.ProgressChanged += new ProgressChangedEventHandler(bgworkerSimStart_ProgressChanged);
					bgworkerSimStart.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgworkerSimStart_RunWorkerCompleted);
					bgworkerSimStart.DoWork += new DoWorkEventHandler(bgworkerSimStart_DoWork);
					bgworkerSimStart.WorkerReportsProgress = true;
					bgworkerSimStart.WorkerSupportsCancellation = true;

					bgworkerSimStart.ReportProgress(2, "Compile Workflow.");
					_currentCompileResults = _wfController.CompileWorkflowForSimulation();
					if ( _currentCompileResults == null || _currentCompileResults.Errors.HasErrors ) {
						this.Cursor = Cursors.Default;
						string msg = "Compilation failed! There are compile errors. Please check the task list for further informations.";
#if DEBUG
						msg += Environment.NewLine + "-------------------- Debug Info --------------------" + Environment.NewLine;
						foreach ( CompilerError error in _currentCompileResults.Errors ) {
							msg += string.Format("{1}{0}", Environment.NewLine, error.ErrorText);
						}
#endif
						MessageBox.Show(msg, "Simulation failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
						this.Close();
						_isExiting = true;
						return false;
					}
				}
				// start simulation workflows
				bgworkerSimStart.RunWorkerAsync();
			} finally {
			}
			return true;
		}
		private bool startWFAsync()
		{
			bgworkerSimStart.ReportProgress(1, "Start Simulation.");
			if ( _currentCompileResults == null || _currentCompileResults.CompiledAssembly == null ) {
				bgworkerSimStart.ReportProgress(2, "Compile Workflow.");
				_currentCompileResults = _wfController.CompileWorkflowForSimulation();
				if ( _currentCompileResults == null || _currentCompileResults.Errors.HasErrors ) {
					return false;
				}
			}
			bgworkerSimStart.ReportProgress(3, "Compilation Completed.");
			_runtime = new WorkflowRuntime();

			bgworkerSimStart.ReportProgress(4, "Initialize Workflow Runtime.");

			TypeProvider typeProvider = new TypeProvider(_runtime);
			typeProvider.AddAssembly(_currentCompileResults.CompiledAssembly);

			#region old code
			//typeProvider.SetLocalAssembly(results.CompiledAssembly);
			//string path = @"D:\Projekte\INTEGRITY\SOBADesigner\OpenComposite.SOBADesigner\bin\Debug\Temp\PO_Orchestration";
			//typeProvider.AddAssemblyReference(Path.Combine(path, results.CompiledAssembly.ManifestModule.Name));
			//typeProvider.AddAssemblyReference(typeof(System.EventHandler).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.ComponentModel.AttributeCollection).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Workflow.ComponentModel.CompositeActivity).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Workflow.Activities.SequentialWorkflowActivity).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Runtime.Serialization.XsdDataContractImporter).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.ServiceModel.EndpointAddress).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Web.Services.WebService).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Xml.XmlDocument).Assembly.Location);
			//typeProvider.AddAssemblyReference(Path.Combine(path, "Microsoft.Web.Services2.dll"));
			//typeProvider.AddAssemblyReference(Path.Combine(path, "OpenComposite.Base.Structures.dll"));
			//typeProvider.AddAssemblyReference(Path.Combine(path, "OpenComposite.Workflow.dll"));
			//typeProvider.AddAssemblyReference(typeof(System.Data.Constraint).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Data.Design.MethodSignatureGenerator).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Drawing.Bitmap).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Drawing.Design.BitmapEditor).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Transactions.CommittableTransaction).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Web.AspNetHostingPermission).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Windows.Forms.Application).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(System.Workflow.Runtime.CorrelationProperty).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(OpenComposite.Base.Structures.ActivityInstance).Assembly.Location);
			//typeProvider.AddAssemblyReference(typeof(OpenComposite.Workflow.LogicalEPActivity).Assembly.Location);
			#endregion

			_trackingsvc = new SimulationTrackingService();
			_trackingsvc.Tracking += new EventHandler<SimulationTrackingEventArgs>(_trackingsvc_Tracking);
			_trackingsvc.CompletedOrTerminated += new EventHandler<SimulationTrackingEventArgs>(_trackingsvc_CompletedOrTerminated);

			_runtime.WorkflowAborted += new EventHandler<WorkflowEventArgs>(_runtime_WorkflowAborted);
			_runtime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(_runtime_WorkflowCompleted);
			_runtime.WorkflowCreated += new EventHandler<WorkflowEventArgs>(_runtime_WorkflowCreated);
			_runtime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(_runtime_WorkflowIdled);
			_runtime.WorkflowLoaded += new EventHandler<WorkflowEventArgs>(_runtime_WorkflowLoaded);
			_runtime.WorkflowPersisted += new EventHandler<WorkflowEventArgs>(_runtime_WorkflowPersisted);
			_runtime.WorkflowResumed += new EventHandler<WorkflowEventArgs>(_runtime_WorkflowResumed);
			_runtime.WorkflowStarted += new EventHandler<WorkflowEventArgs>(_runtime_WorkflowStarted);
			_runtime.WorkflowSuspended += new EventHandler<WorkflowSuspendedEventArgs>(_runtime_WorkflowSuspended);
			_runtime.WorkflowTerminated += new EventHandler<WorkflowTerminatedEventArgs>(_runtime_WorkflowTerminated);
			_runtime.WorkflowUnloaded += new EventHandler<WorkflowEventArgs>(_runtime_WorkflowUnloaded);

			_runtime.AddService(_trackingsvc);
			_runtime.AddService(typeProvider);

			_runtime.StartRuntime();
			bgworkerSimStart.ReportProgress(5, "Workflow Runtime Started.");

			WorkflowInstance wfInst = null;
			bgworkerSimStart.ReportProgress(6, "Initialize and Start Simulation Cycles.");
			if ( rbnDocuments.Checked ) {
				#region Document Flow
				Dictionary<string, object> dicArgs = new Dictionary<string, object>();
				boTvTrackedDocuments.Model = null;
				dicArgs.Add(PropertyNames.IsSimulation, true);
				dicArgs.Add(PropertyNames.IsDocumentFlowSimulation, rbnDocuments.Checked);
				dicArgs.Add(PropertyNames.SimulateAllLogicalActivities, rbSimAllLogActs.Checked);

				SimulationVariable inputObject = businessObjectTreeView1.RootNode as SimulationVariable;
				businessObjectTreeView1.CompiledAssembly = _currentCompileResults.CompiledAssembly;
				if ( inputObject != null ) {
					dicArgs.Add(inputObject.VarName, businessObjectTreeView1.CreateInputObject(inputObject));
				}
				Type typeWF = typeProvider.GetType(this._wfController.FullClassName);

				if ( typeWF != null ) {
					wfInst = _runtime.CreateWorkflow(typeWF, dicArgs);
				}
				if ( wfInst != null ) {
					// remove WebServiceInput/Output Activities
					Activity definition = wfInst.GetWorkflowDefinition();
					WorkflowChanges changes = new WorkflowChanges(definition);
					CompositeActivity root = changes.TransientWorkflow;

					bool changed = removeWebSvcInOutActivitiesRecursive(root);
					try {
						if ( changed )
							wfInst.ApplyWorkflowChanges(changes);
					} catch { }
					_lstInstances.Add(wfInst.InstanceId);
					wfInst.Start();
					bgworkerSimStart.ReportProgress(0, "");
				} else {
					return false;
				}
				#endregion
			} else {
				#region Process Flow
				foreach ( DataRow row in dtSimCycles.Rows ) {

					Dictionary<string, object> dicArgs = new Dictionary<string, object>();
					dicArgs.Add(PropertyNames.IsSimulation, true);
					dicArgs.Add(PropertyNames.SimulateAllLogicalActivities, rbSimAllLogActs.Checked);
					foreach ( DataColumn col in dtSimCycles.Columns ) {
						if ( col.Ordinal > 0 && row[col] != col.DefaultValue )
							dicArgs.Add(col.ColumnName, row[col]);
					}
					Type typeWF = typeProvider.GetType(this._wfController.FullClassName);

					if ( typeWF != null ) {
						wfInst = _runtime.CreateWorkflow(typeWF, dicArgs);
					}
					if ( wfInst != null ) {
						// remove WebServiceInput/Output Activities
						Activity definition = wfInst.GetWorkflowDefinition();
						WorkflowChanges changes = new WorkflowChanges(definition);
						CompositeActivity root = changes.TransientWorkflow;
						bool changed = removeWebSvcInOutActivitiesRecursive(root);
						try {
							if ( changed )
								wfInst.ApplyWorkflowChanges(changes);
						} catch {
						}
						_lstInstances.Add(wfInst.InstanceId);
						wfInst.Start();
						bgworkerSimStart.ReportProgress(0, "");
					} else {
						return false;
					}
				}
				#endregion
			}
			return true;
		}

		private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			try {
				if ( _currentCompileResults.CompiledAssembly != null &&
					 args.Name.StartsWith(_currentCompileResults.CompiledAssembly.FullName) ) {
					//string[] nm = args.Name.Split(',');
					//string path = @"D:\Projekte\INTEGRITY\SOBADesigner\OpenComposite.SOBADesigner\bin\Debug\Temp\PO_Orchestration";
					//string file = Path.Combine(path, nm[0] + ".dll");
					//Assembly asm = Assembly.LoadFile(file);
					return _currentCompileResults.CompiledAssembly;
				}
			} catch {
			}
			return null;
		}
		private bool removeWebSvcInOutActivitiesRecursive(CompositeActivity composite)
		{
			bool changed = false;
			List<Activity> lstRemove = new List<Activity>();
			List<CompositeActivity> lstComposites = new List<CompositeActivity>();
			foreach ( Activity act in composite.Activities ) {
				if ( act is WebServiceInputActivity || act is WebServiceOutputActivity ||
					 act is HandleExternalEventActivity || act is CallExternalMethodActivity )
					lstRemove.Add(act);
				else if ( act is CompositeActivity )
					lstComposites.Add((CompositeActivity)act);
			}
			foreach ( Activity act in lstRemove ) {
				if ( !changed )
					changed = true;
				composite.Activities.Remove(act);
				//act.Enabled = false;
			}
			foreach ( CompositeActivity cact in lstComposites ) {
				if ( removeWebSvcInOutActivitiesRecursive(cact) )
					changed = true;
			}
			return changed;
		}
		private void stopWF()
		{
			try {
				if ( _trackingsvc != null ) {
					_trackingsvc.Tracking -= new EventHandler<SimulationTrackingEventArgs>(_trackingsvc_Tracking);
					_trackingsvc.CompletedOrTerminated -= new EventHandler<SimulationTrackingEventArgs>(_trackingsvc_CompletedOrTerminated);
					_trackingsvc = null;
				}
			} catch { }
			try {
				if ( _runtime != null ) {
					//foreach ( WorkflowInstance wi in _runtime.GetLoadedWorkflows() ) {
					//    wi.Abort.Terminate("Stop Simulation.");
					//}
					//_runtime.StopRuntime();
					_runtime.WorkflowAborted -= new EventHandler<WorkflowEventArgs>(_runtime_WorkflowAborted);
					_runtime.WorkflowCompleted -= new EventHandler<WorkflowCompletedEventArgs>(_runtime_WorkflowCompleted);
					_runtime.WorkflowCreated -= new EventHandler<WorkflowEventArgs>(_runtime_WorkflowCreated);
					_runtime.WorkflowIdled -= new EventHandler<WorkflowEventArgs>(_runtime_WorkflowIdled);
					_runtime.WorkflowLoaded -= new EventHandler<WorkflowEventArgs>(_runtime_WorkflowLoaded);
					_runtime.WorkflowPersisted -= new EventHandler<WorkflowEventArgs>(_runtime_WorkflowPersisted);
					_runtime.WorkflowResumed -= new EventHandler<WorkflowEventArgs>(_runtime_WorkflowResumed);
					_runtime.WorkflowStarted -= new EventHandler<WorkflowEventArgs>(_runtime_WorkflowStarted);
					_runtime.WorkflowSuspended -= new EventHandler<WorkflowSuspendedEventArgs>(_runtime_WorkflowSuspended);
					_runtime.WorkflowTerminated -= new EventHandler<WorkflowTerminatedEventArgs>(_runtime_WorkflowTerminated);
					_runtime.WorkflowUnloaded -= new EventHandler<WorkflowEventArgs>(_runtime_WorkflowUnloaded);

					_runtime.Dispose();
					_runtime = null;
				}
			} catch { }
		}
		private void addTrackingData(Guid wfinstance, string type, string name, string info)
		{
			try {
				this.Data.Rows.Add(this.Data.Rows.Count + 1, DateTime.Now, type, name, info, wfinstance);
			} catch ( Exception ex ) {
				Debug.WriteLine(ex.ToString());
			}
		}

		private void setButtons(bool simStarted)
		{
			btnStartSim.Text = simStarted ? "Stop Simulation" : "Compile && Start Simulation";
			tsbtnCompileStart.Enabled = !simStarted;
			tsbtnCompileStart.Visible = !simStarted;
			tsbtnSimStart.Enabled = !simStarted;
			tsbtnSimStart.Visible = !simStarted;
			tsbtnSimStop.Enabled = simStarted;
		}
		private void calculateSimCycles()
		{
			if ( dtSimCycles != null ) {
				dtSimCycles.Dispose();
			}
			dtSimCycles = new DataTable();
			dtSimCycles.Columns.Add("Index", typeof(int));
			foreach ( DataRow row in dtSimVars.Rows ) {
				DataColumn col = dtSimCycles.Columns.Add(row[dcSVVarName].ToString(),
											Helpers.GetDotNetTypeOfDataTypeString(row[dcSVDataType].ToString()));
				col.ExtendedProperties.Add(_DISTRIBUTION, row[dcSVDistribution]);
			}
			//if ( _customSimCyclesCount ) {
			int count = 0;
			if ( string.IsNullOrEmpty(tscmbCycles.Text) ) tscmbCycles.Text = "1";
			if ( !int.TryParse(tscmbCycles.Text, out count) ) {
				MessageBox.Show("Please enter a number.");
				tscmbCycles.Focus();
				tscmbCycles.SelectAll();
				return;
			}
			for ( int i = 0; i < count; i++ ) {
				DataRow row = dtSimCycles.NewRow();
				foreach ( DataColumn col in dtSimCycles.Columns ) {
					if ( col.Ordinal == 0 )
						row[col] = i;
					else
						calculateSimCycleRowItem(row, col, i, count);
				}
				dtSimCycles.Rows.Add(row);
			}
			//} else {
			//    try {
			//        calculateSimCyclesRecursive(0, null);
			//    } catch ( Exception ex ) {
			//        MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
			//    }
			//    tscmbCycles.Text = dtSimCycles.Rows.Count.ToString();
			//}
		}
		private void calculateSimCyclesRecursive(int indexSimVar, DataRow rowCycle)
		{
			if ( dtSimVars.Rows.Count <= indexSimVar )
				return;

			bool isFirst = true;
			DataRow drCurrent = dtSimVars.Rows[indexSimVar];
			//DataRow drCycleCurrent;
			Type type = Helpers.GetDotNetTypeOfDataTypeString(drCurrent[dcSVDataType].ToString());
			if ( type == null )
				return;

			if ( type == typeof(int) ) {
				#region calculate int values
				int v1, v2, step;
				if ( !int.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = 0;
				if ( !int.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = 0;
				if ( !int.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = 0;
				if ( step != 0 ) {
					for ( int i = v1; ( step > 0 ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else if ( type == typeof(uint) ) {
				#region calculate int values
				uint v1, v2, step;
				if ( !uint.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = 0;
				if ( !uint.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = 0;
				if ( !uint.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = 0;
				if ( step != 0 ) {
					for ( uint i = v1; ( step > 0 ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else if ( type == typeof(double) ) {
				#region calculate double values
				double v1, v2, step;
				if ( !double.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = 0d;
				if ( !double.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = 0d;
				if ( !double.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = 0d;
				if ( step != 0d ) {
					for ( double i = v1; ( step > 0d ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else if ( type == typeof(float) ) {
				#region calculate float values
				float v1, v2, step;
				if ( !float.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = 0f;
				if ( !float.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = 0f;
				if ( !float.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = 0f;
				if ( step != 0f ) {
					for ( float i = v1; ( step > 0f ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else if ( type == typeof(decimal) ) {
				#region calculate decimal values
				decimal v1, v2, step;
				if ( !decimal.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = 0m;
				if ( !decimal.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = 0m;
				if ( !decimal.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = 0m;
				if ( step != 0m ) {
					for ( decimal i = v1; ( step > 0m ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else if ( type == typeof(long) ) {
				#region calculate long values
				long v1, v2, step;
				if ( !long.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = 0L;
				if ( !long.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = 0L;
				if ( !long.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = 0L;
				if ( step != 0L ) {
					for ( long i = v1; ( step > 0L ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else if ( type == typeof(ulong) ) {
				#region calculate long values
				ulong v1, v2, step;
				if ( !ulong.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = 0L;
				if ( !ulong.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = 0L;
				if ( !ulong.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = 0L;
				if ( step != 0L ) {
					for ( ulong i = v1; ( step > 0L ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else if ( type == typeof(bool) ) {
				#region calculate bool values
				bool v1, v2;
				if ( !bool.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = true;
				if ( !bool.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = true;
				rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
				rowCycle[indexSimVar + 1] = v1;
				calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
				if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v2;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
				}
				#endregion
			} else if ( type == typeof(string) ) {
				#region calculate string values
				string v1, v2;
				v1 = drCurrent[dcSVStartValue].ToString();
				v2 = drCurrent[dcSVEndValue].ToString();
				if ( !string.IsNullOrEmpty(v1) ) {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
				}
				if ( !string.IsNullOrEmpty(v2) ) {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v2;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
				}
				#endregion
			} else if ( type == typeof(DateTime) ) {
				#region calculate DateTime values
				DateTime v1, v2;
				TimeSpan step;
				if ( !DateTime.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = DateTime.MinValue;
				if ( !DateTime.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = DateTime.MinValue;
				if ( !TimeSpan.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = TimeSpan.Zero;
				if ( step != TimeSpan.Zero ) {
					for ( DateTime i = v1; ( step > TimeSpan.Zero ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else if ( type == typeof(TimeSpan) ) {
				#region calculate TimeSpan values
				TimeSpan v1, v2, step;
				if ( !TimeSpan.TryParse(drCurrent[dcSVStartValue].ToString(), out v1) )
					v1 = TimeSpan.Zero;
				if ( !TimeSpan.TryParse(drCurrent[dcSVEndValue].ToString(), out v2) )
					v2 = TimeSpan.Zero;
				if ( !TimeSpan.TryParse(drCurrent[dcSVSteps].ToString(), out step) )
					step = TimeSpan.Zero;
				if ( step != TimeSpan.Zero ) {
					for ( TimeSpan i = v1; ( step > TimeSpan.Zero ? i <= v2 : i >= v2 ); i = i + step ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = i;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				} else {
					rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
					rowCycle[indexSimVar + 1] = v1;
					calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					if ( !string.IsNullOrEmpty(drCurrent[dcSVEndValue].ToString()) ) {
						rowCycle = getNewSimCycleRow(rowCycle, ref isFirst);
						rowCycle[indexSimVar + 1] = v2;
						calculateSimCyclesRecursive(indexSimVar + 1, rowCycle);
					}
				}
				#endregion
			} else {
				throw new NotSupportedException(string.Format("Type '{0}' not supported by calculation of simulation cycles.", type.ToString()));
			}
		}
		private void calculateSimCycleRowItem(DataRow row, DataColumn column, int index, int count)
		{
			Distribution distribution = Distribution.None;
			if ( column.ExtendedProperties[_DISTRIBUTION] != null &&
				column.ExtendedProperties[_DISTRIBUTION] != DBNull.Value ) {
				distribution = (Distribution)Enum.Parse(typeof(Distribution), column.ExtendedProperties[_DISTRIBUTION].ToString());
			}

			// decrement because the first column in dtSimCycles is the "Index" column
			DataRow drCurrent = dtSimVars.Rows[column.Ordinal - 1];
			Type type = column.DataType;
			decimal step;
			if ( !decimal.TryParse(drCurrent[dcSVSteps].ToString().Replace(',', '.'),
					NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out step) ) {
				step = 1;
			} else {
			}
			try {
				if ( type == typeof(int) ) {
					#region calculate int values
					int v1, v2;
					bool v1ok = int.TryParse(drCurrent[dcSVStartValue].ToString(), out v1);
					bool v2ok = int.TryParse(drCurrent[dcSVEndValue].ToString(), out v2);

					if ( v1ok && v2ok ) {
						if ( v2 > v1 ) {
							row[column] = getValueByDistribution(v1, v2, distribution, (int)step, index, count);
						} else {
							row[column] = getValueByDistribution(v2, v1, distribution, (int)step, index, count);
						}
						//_random.Next(v1, v2 + 1);
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else if ( type == typeof(double) ) {
					#region calculate double values
					double v1, v2;
					bool v1ok = double.TryParse(drCurrent[dcSVStartValue].ToString(), out v1);
					bool v2ok = double.TryParse(drCurrent[dcSVEndValue].ToString(), out v2);
					if ( v1ok && v2ok ) {
						//row[column] = _random.NextDouble() * ( v2 - v1 ) + v1;
						if ( v2 > v1 ) {
							row[column] = (double)getValueByDistribution((decimal)v1, (decimal)v2, distribution, step, index, count);
						} else {
							row[column] = (double)getValueByDistribution((decimal)v2, (decimal)v1, distribution, step, index, count);
						}
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else if ( type == typeof(float) ) {
					#region calculate float values
					float v1, v2;
					bool v1ok = float.TryParse(drCurrent[dcSVStartValue].ToString(), out v1);
					bool v2ok = float.TryParse(drCurrent[dcSVEndValue].ToString(), out v2);
					if ( v1ok && v2ok ) {
						//row[column] = (float)( _random.NextDouble() * ( v2 - v1 ) + v1 );
						if ( v2 > v1 ) {
							row[column] = (float)getValueByDistribution((decimal)v1, (decimal)v2, distribution, step, index, count);
						} else {
							row[column] = (float)getValueByDistribution((decimal)v2, (decimal)v1, distribution, step, index, count);
						}
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else if ( type == typeof(decimal) ) {
					#region calculate decimal values
					decimal v1, v2;
					bool v1ok = decimal.TryParse(drCurrent[dcSVStartValue].ToString(), out v1);
					bool v2ok = decimal.TryParse(drCurrent[dcSVEndValue].ToString(), out v2);
					if ( v1ok && v2ok ) {
						if ( v2 > v1 ) {
							row[column] = getValueByDistribution(v1, (decimal)v2, distribution, step, index, count);
						} else {
							row[column] = getValueByDistribution((decimal)v2, v1, distribution, step, index, count);
						}
						//row[column] = (decimal)( (decimal)_random.NextDouble() * ( v2 - v1 ) + v1 );
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else if ( type == typeof(long) ) {
					#region calculate long values
					long v1, v2;
					bool v1ok = long.TryParse(drCurrent[dcSVStartValue].ToString(), out v1);
					bool v2ok = long.TryParse(drCurrent[dcSVEndValue].ToString(), out v2);
					if ( v1ok && v2ok ) {
						//row[column] = (long)( _random.NextDouble() * ( v2 - v1 ) + v1 );
						if ( v2 > v1 ) {
							row[column] = (long)getValueByDistribution((decimal)v1, (decimal)v2, distribution, step, index, count);
						} else {
							row[column] = (long)getValueByDistribution((decimal)v2, (decimal)v1, distribution, step, index, count);
						}
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else if ( type == typeof(bool) ) {
					#region calculate bool values
					bool v1, v2;
					bool v1ok = bool.TryParse(drCurrent[dcSVStartValue].ToString(), out v1);
					bool v2ok = bool.TryParse(drCurrent[dcSVEndValue].ToString(), out v2);
					if ( v1ok && v2ok ) {
						row[column] = _random.NextDouble() >= .5 ? v1 : v2;
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else if ( type == typeof(string) ) {
					#region calculate string values
					string v1, v2;
					v1 = drCurrent[dcSVStartValue].ToString();
					v2 = drCurrent[dcSVEndValue].ToString();
					bool v1ok = !string.IsNullOrEmpty(v1);
					bool v2ok = !string.IsNullOrEmpty(v2);
					if ( v1ok && v2ok ) {
						row[column] = _random.NextDouble() >= .5 ? v1 : v2;
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else if ( type == typeof(DateTime) ) {
					#region calculate DateTime values
					DateTime v1, v2;
					bool v1ok = DateTime.TryParse(drCurrent[dcSVStartValue].ToString(), out v1);
					bool v2ok = DateTime.TryParse(drCurrent[dcSVEndValue].ToString(), out v2);
					if ( v1ok && v2ok ) {
						row[column] = v1.AddTicks((long)( _random.NextDouble() * ( v2.Ticks - v1.Ticks ) + v1.Ticks ));
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else if ( type == typeof(TimeSpan) ) {
					#region calculate TimeSpan values
					TimeSpan v1, v2;
					bool v1ok = TimeSpan.TryParse(drCurrent[dcSVStartValue].ToString(), out v1);
					bool v2ok = TimeSpan.TryParse(drCurrent[dcSVEndValue].ToString(), out v2);
					if ( v1ok && v2ok ) {
						row[column] = v1.Add(new TimeSpan((long)( _random.NextDouble() * ( v2.Ticks - v1.Ticks ) + v1.Ticks )));
					} else if ( v1ok ) {
						row[column] = v1;
					} else if ( v2ok ) {
						row[column] = v2;
					}
					#endregion
				} else {
					throw new NotSupportedException(string.Format("Type '{0}' not supported by calculation of simulation cycles.", type.ToString()));
				}
			} catch ( DivideByZeroException ) {
				MessageBox.Show("There was an error calculating the simulation cycles. Please verify you simulation variables!",
					"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private int getValueByDistribution(int v1, int v2, Distribution distribution, int step, int index, int count)
		{
			switch ( distribution ) {
				case Distribution.None:
					int maxUniques = 0;
					for ( decimal i = v1; i <= v2; i += ( step == 0 ? 1 : step ) ) {
						maxUniques++;
					}
					int currentMulti = (int)Math.Floor((decimal)index / maxUniques);
					int currentInc = index - ( currentMulti * maxUniques );
					return v1 + ( currentInc * ( step == 0 ? 1 : step ) );
				case Distribution.Rectangular:
					return _random.Next(v1, v2);
				case Distribution.Normal:
					return (int)( NextNormal() * ( v2 - v1 ) + v1 );
				default:
					return 0;
			}
		}
		private decimal getValueByDistribution(decimal v1, decimal v2, Distribution distribution, decimal step, int index, int count)
		{
			switch ( distribution ) {
				case Distribution.None:
					// the number of unique results
					// e.g. Start: 2, End: 10, Step: 3, Unique Results: {2;5;8} = 3
					int maxUniques = 0;
					if ( step < 0 ) {
						for ( decimal i = v2; i <= v1; i += -step ) {
							maxUniques++;
						}
					} else if ( step > 0 ) {
						for ( decimal i = v1; i <= v2; i += step ) {
							maxUniques++;
						}
					} else {
						for ( decimal i = v1; i <= v2; i += 1 ) {
							maxUniques++;
						}
					}
					// the current multiplier (times the uniques have been through)
					// for the example above: if index is 4, uniques have been through 1 time
					int currentMulti = (int)Math.Floor((decimal)index / maxUniques);
					// current base increment (always less than maxUniques)
					int currentInc = index - ( currentMulti * maxUniques );
					// () arrount the ?: construct are neccessary here. => Order of Operations!
					return v1 + ( currentInc * ( step == 0 ? 1 : step ) );
				case Distribution.Rectangular: {
						decimal result;
						if ( step != 0 ) {
							int num = 0;
							List<decimal> results = new List<decimal>();
							for ( decimal i = v1; i <= v2; i += step ) {
								results.Add(i);
								num++;
							}
							result = results[_random.Next(num)];
						} else {
							result = (decimal)_random.NextDouble() * ( v2 - v1 ) + v1;
						}
						//result = result - ( result % step );
						return result;
					}
				case Distribution.Normal: {
						decimal result;
						if ( step != 0 ) {
							int num = 0;
							List<decimal> results = new List<decimal>();
							for ( decimal i = v1; i <= v2; i += step ) {
								results.Add(i);
								num++;
							}
							try {
								result = results[(int)( NextNormal() * num )];
							} catch { result = 0; }
						} else {
							result = NextNormal() * ( v2 - v1 ) + v1;
							//result = result - (result % step);
						}
						return result;
					}
				default:
					return 0;
			}
		}

		private decimal NextNormal()
		{
			decimal x = 0;
			for ( int i = 0; i < 4; i++ ) x += (decimal)_random.NextDouble();
			return x / 4;
		}
		//private string getValueByDistribution(string v1, string v2, Distribution distribution, int index)
		//{
		//    switch ( distribution ) {
		//        case Distribution.None:
		//            break;
		//        case Distribution.Rectangular:
		//            break;
		//        case Distribution.Normal:
		//            break;
		//        default:
		//            break;
		//    }
		//}
		//private DateTime getValueByDistribution(DateTime v1, DateTime v2, Distribution distribution, int index)
		//{
		//    switch ( distribution ) {
		//        case Distribution.None:
		//            break;
		//        case Distribution.Rectangular:
		//            break;
		//        case Distribution.Normal:
		//            break;
		//        default:
		//            break;
		//    }
		//}
		//private TimeSpan getValueByDistribution(TimeSpan v1, TimeSpan v2, Distribution distribution, int index)
		//{
		//    switch ( distribution ) {
		//        case Distribution.None:
		//            break;
		//        case Distribution.Rectangular:
		//            break;
		//        case Distribution.Normal:
		//            break;
		//        default:
		//            break;
		//    }
		//}

		private DataRow getNewSimCycleRow(DataRow rowMaster, ref bool isFirst)
		{
			DataRow newrow;
			if ( isFirst ) {
				if ( rowMaster != null )
					newrow = rowMaster;
				else {
					newrow = dtSimCycles.NewRow();
					newrow[0] = dtSimCycles.Rows.Count;
					dtSimCycles.Rows.Add(newrow);
				}
				isFirst = false;
			} else {
				newrow = dtSimCycles.NewRow();
				newrow[0] = dtSimCycles.Rows.Count;
				if ( rowMaster != null ) {
					for ( int i = 1; i < rowMaster.Table.Columns.Count; i++ ) {
						newrow[i] = rowMaster[i];
					}
				}
				dtSimCycles.Rows.Add(newrow);
			}
			return newrow;
		}

		private void showProgress()
		{
			if ( rbnDocuments.Checked ) {
				if ( tsprogressSim.Value + 1 > tsprogressSim.Maximum ) tsprogressSim.Maximum++;
			}
			tsprogressSim.Value += 1;

			if ( rbnProcess.Checked ) {
				if ( _completedCount == dtSimCycles.Rows.Count ) endSimulation();
			} else if ( rbnDocuments.Checked ) {
				if ( _completedCount == 1 ) endSimulation();
			}
		}

		private void addKPITrackingDataToResults(Guid guidWFInstance, string nameActivity,
												 OpenComposite.Workflow.KPITrackingData data)
		{
			lock ( lockThis ) {
				if ( !_lstActNames.Contains(nameActivity) )
					_lstActNames.Add(nameActivity);
				bool isNew = false;
				DataRow row = null;
				DataRow[] rows = dtResults.Select("InstanceId = " + _lstInstances.IndexOf(guidWFInstance).ToString() +
												  " AND ActivityName = '" + nameActivity + "'");
				if ( rows.Length > 0 ) {
					row = rows[0];
				} else {
					row = dtResults.NewRow();
					row[0] = _lstInstances.IndexOf(guidWFInstance);
					row[1] = nameActivity;
					isNew = true;
				}
				try {
					if ( dtResults.Columns.Contains(data.Name) ) {
						Type type = dtResults.Columns[data.Name].DataType;
						#region parse data.Value
						if ( type == typeof(int) ) {
							int val;
							if ( int.TryParse(data.Value, NumberStyles.Float,
								CultureInfo.InvariantCulture.NumberFormat, out val) ) {
								row[data.Name] = val;
							}
						} else if ( type == typeof(long) ) {
							long val;
							if ( long.TryParse(data.Value, NumberStyles.Float,
								CultureInfo.InvariantCulture.NumberFormat, out val) ) {
								row[data.Name] = val;
							}
						} else if ( type == typeof(double) ) {
							double val;
							if ( double.TryParse(data.Value, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out val) ) {
								row[data.Name] = val;
							} else if ( double.TryParse(data.Value, out val) ) {
								row[data.Name] = val;
							}
						} else if ( type == typeof(float) ) {
							float val;
							if ( float.TryParse(data.Value, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out val) ) {
								row[data.Name] = val;
							} else if ( float.TryParse(data.Value, out val) ) {
								row[data.Name] = val;
							}
						} else if ( type == typeof(decimal) ) {
							decimal val;
							if ( decimal.TryParse(data.Value, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out val) ) {
								row[data.Name] = val;
							} else if ( decimal.TryParse(data.Value, out val) ) {
								row[data.Name] = val;
							}
						} else if ( type == typeof(DateTime) ) {
							DateTime val;
							if ( DateTime.TryParse(data.Value, out val) ) {
								row[data.Name] = val;
							}
						} else if ( type == typeof(TimeSpan) ) {
							TimeSpan val;
							if ( TimeSpan.TryParse(data.Value, out val) ) {
								row[data.Name] = val;
							}
						} else if ( type == typeof(bool) ) {
							bool val;
							if ( bool.TryParse(data.Value, out val) ) {
								row[data.Name] = val;
							}
						} else if ( type == typeof(string) ) {
							row[data.Name] = data.Value;
						} else {
							throw new NotSupportedException(string.Format("Type '{0}' not supported by tracking.", type.ToString()));
						}
						#endregion
					}
					if ( dtResults.Columns.Contains(data.Name + "_Unit") ) {
						row[data.Name + "_Unit"] = data.Unit;
					}
				} catch {
					row = null;
				}
				if ( row != null && isNew )
					dtResults.Rows.Add(row);
			}
		}

		private void showResults(string colname)
		{
			KpiUnit kpiUnit = cmbUnitOfMeasurement.SelectedItem as KpiUnit;
			string unit = null;
			if ( kpiUnit != null ) {
				unit = kpiUnit.Name;
			}
			dgvResults.DataSource = dtResults;
			if ( dtResults.Columns.Count <= 2 )
				return;

			ReportDataList rdl = new ReportDataList();
			BindingListEx<KeyPerformanceIndicator> kpis = Global.Data.GetKeyPerformanceIndicatiors();

			foreach ( string actnm in _lstActNames ) {
				DataRow[] rowsAct = dtResults.Select("ActivityName = '" + actnm + "'");
				if ( rowsAct.Length > 0 ) {
					foreach ( KeyPerformanceIndicator kpi in kpis ) {
						string kpiname = kpi.Name;
						if ( !rowsAct[0].IsNull(kpiname) &&
							 ( string.IsNullOrEmpty(colname) || colname == kpiname ) ) {
							rdl.Add(actnm, kpiname, rowsAct[0][kpiname]);
						}
					}
				}
			}
			DataRow[] rowsAvg = dtResultSummary.Select("InstanceId = '" + _PROCESS + "'");
			if ( rowsAvg.Length > 0 ) {
				foreach ( KeyPerformanceIndicator kpi in kpis ) {
					string kpiname = kpi.Name;
					if ( !rowsAvg[0].IsNull(kpiname) &&
						 ( string.IsNullOrEmpty(colname) || colname == kpiname ) ) {
						rdl.Add(_PROCESS, kpiname, rowsAvg[0][kpiname]);
					}
				}
			}

			if ( !string.IsNullOrEmpty(colname) ) {
				KeyPerformanceIndicator colKpi = Global.Data.GetKeyPerformanceIndicatior(colname);
				if ( colKpi != null ) {
					if ( !string.IsNullOrEmpty(unit) ) {
						foreach ( ReportData data in rdl.Data ) {
							data.KPIName = string.Format("{0} ({1})", data.KPIName, unit);
							data.Value = Helpers.ConvertUnit(data.Value, colKpi.BaseUnit, colKpi.GetKpiUnit(unit));
						}
					}
				}
			}

			this.ReportDataBindingSource.DataSource = rdl.Data;
			this.reportSimResult.RefreshReport();
		}
		private void showResultsSummary(string colname)
		{
			if ( dtResultSummary.Columns.Count <= 1 )
				return;

			this.ReportDataBindingSource.DataSource = null;
			ReportDataList rdl = new ReportDataList();
			foreach ( DataRow row in dtResultSummary.Rows ) {
				for ( int i = 1; i < dtResultSummary.Columns.Count; i++ ) {
					if ( !dtResultSummary.Columns[i].ColumnName.EndsWith("_Unit") && !row.IsNull(i) ) {
						if ( string.IsNullOrEmpty(colname) ||
							 colname.EndsWith("_Unit") ||
							 colname == dtResultSummary.Columns[i].ColumnName )
							rdl.Add(row[0].ToString(), dtResultSummary.Columns[i].ToString(), row[i]);
					}
				}
			}
			this.ReportDataBindingSource.DataSource = rdl.Data;
			this.reportSimResult.RefreshReport();
		}
		private void calculateSummary()
		{
			dgvResultsSummery.DataSource = null;
			dtResultSummary.DefaultView.Sort = "";
			dtResultSummary.Clear();
			while ( dtResultSummary.Columns.Count > 1 ) dtResultSummary.Columns.RemoveAt(1);
			//DataTable dtKPI = Global.Data.SelectRepositoryTableComplete(OpenComposite.EII.Repository.ItemType.KPI);
			//foreach ( DataRow dr in dtKPI.Rows ) {
			//    string kpiname = dr["kpi_nm"].ToString();
			//    dtResultSummary.Columns.Add(kpiname,
			//        Helpers.GetDotNetTypeOfDataTypeString(dr["kpi_datatype"].ToString()));
			//    if ( !string.IsNullOrEmpty(dr["kpi_units"] as string) ) {
			//        dtResultSummary.Columns.Add(kpiname + "_Unit", typeof(string));
			//    }
			//}
			BindingListEx<KeyPerformanceIndicator> kpis = Global.Data.GetKeyPerformanceIndicatiors();
			foreach ( KeyPerformanceIndicator kpi in kpis ) {
				string kpiname = kpi.Name;
				dtResultSummary.Columns.Add(kpiname,
					Helpers.GetDotNetTypeOfDataTypeString(kpi.DataType));
				if ( kpi.ExtendedProperties.Units.Count > 0 ) {
					dtResultSummary.Columns.Add(kpiname + "_Unit", typeof(string));
				}
			}
			DataRow rowAll = dtResultSummary.NewRow();
			rowAll[0] = _PROCESS;
			foreach ( Guid idInst in _lstInstances ) {
				DataRow[] rows = dtResults.Select("InstanceId = '" + _lstInstances.IndexOf(idInst).ToString() + "'");
				DataRow rowInstance = dtResultSummary.NewRow();
				rowInstance[0] = _lstInstances.IndexOf(idInst).ToString();
				foreach ( KeyPerformanceIndicator kpi in kpis ) {
					//string unit = null;
					bool hasUnit = false;
					string kpiname = kpi.Name;
					string kpicalc = kpi.CalculationType;
					string kpinullvalue = kpi.NullValue == null ? "0" : kpi.NullValue.ToString();
					Type type = Helpers.GetDotNetTypeOfDataTypeString(kpi.DataType);
					hasUnit = true;
					if ( rows.Length == 0 ) {
						if ( type == typeof(int) ) {
							int val = 0;
							int.TryParse(kpinullvalue, out val);
							rowInstance[kpiname] = val;
						} else if ( type == typeof(long) ) {
							long val = 0;
							long.TryParse(kpinullvalue, out val);
							rowInstance[kpiname] = val;
						} else if ( type == typeof(double) ) {
							double val = 0;
							double.TryParse(kpinullvalue, out val);
							rowInstance[kpiname] = val;
						} else if ( type == typeof(float) ) {
							float val = 0;
							float.TryParse(kpinullvalue, out val);
							rowInstance[kpiname] = val;
						} else if ( type == typeof(decimal) ) {
							decimal val = 0;
							decimal.TryParse(kpinullvalue, out val);
							rowInstance[kpiname] = val;
						} else {
						}
					} else {
						foreach ( DataRow drAct in rows ) {
							if ( drAct.IsNull(kpiname) )
								continue;
							if ( hasUnit && !drAct.IsNull(kpiname + "_Unit") ) {
								hasUnit = false;
								rowInstance[kpiname + "_Unit"] = drAct[kpiname + "_Unit"];
							}
							#region calcule summary
							if ( type == typeof(int) ) {
								int val = (int)drAct[kpiname];
								switch ( kpicalc ) {
									case "+":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (int)rowInstance[kpiname] + val;
										break;
									case "*":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (int)rowInstance[kpiname] * val;
										break;
								}
							} else if ( type == typeof(long) ) {
								long val = (long)drAct[kpiname];
								switch ( kpicalc ) {
									case "+":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (long)rowInstance[kpiname] + val;
										break;
									case "*":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (long)rowInstance[kpiname] * val;
										break;
								}
							} else if ( type == typeof(double) ) {
								double val = (double)drAct[kpiname];
								switch ( kpicalc ) {
									case "+":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (double)rowInstance[kpiname] + val;
										break;
									case "*":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (double)rowInstance[kpiname] * val;
										break;
								}
							} else if ( type == typeof(float) ) {
								float val = (float)drAct[kpiname];
								switch ( kpicalc ) {
									case "+":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (float)rowInstance[kpiname] + val;
										break;
									case "*":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (float)rowInstance[kpiname] * val;
										break;
								}
							} else if ( type == typeof(decimal) ) {
								decimal val = (decimal)drAct[kpiname];
								switch ( kpicalc ) {
									case "+":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (decimal)rowInstance[kpiname] + val;
										break;
									case "*":
										rowInstance[kpiname] = rowInstance.IsNull(kpiname) ? val : (decimal)rowInstance[kpiname] * val;
										break;
								}
							} else {
							}
							#endregion
						}
					}
					#region calcule overall summary
					if ( !rowInstance.IsNull(kpiname) ) {
						if ( type == typeof(int) ) {
							int val = (int)rowInstance[kpiname];
							rowAll[kpiname] = rowAll.IsNull(kpiname) ? val : (int)rowAll[kpiname] + val;
						} else if ( type == typeof(long) ) {
							long val = (long)rowInstance[kpiname];
							rowAll[kpiname] = rowAll.IsNull(kpiname) ? val : (long)rowAll[kpiname] + val;
						} else if ( type == typeof(double) ) {
							double val = (double)rowInstance[kpiname];
							rowAll[kpiname] = rowAll.IsNull(kpiname) ? val : (double)rowAll[kpiname] + val;
						} else if ( type == typeof(float) ) {
							float val = (float)rowInstance[kpiname];
							rowAll[kpiname] = rowAll.IsNull(kpiname) ? val : (float)rowAll[kpiname] + val;
						} else if ( type == typeof(decimal) ) {
							decimal val = (decimal)rowInstance[kpiname];
							rowAll[kpiname] = rowAll.IsNull(kpiname) ? val : (decimal)rowAll[kpiname] + val;
						} else {
						}
					}
					#endregion

				}
				dtResultSummary.Rows.Add(rowInstance);
			}
			foreach ( KeyPerformanceIndicator kpi in kpis ) {
				string kpiname = kpi.Name;
				Type type = Helpers.GetDotNetTypeOfDataTypeString(kpi.DataType);
				if ( !rowAll.IsNull(kpiname) ) {
					if ( type == typeof(int) ) {
						rowAll[kpiname] = (int)( (int)rowAll[kpiname] / _lstInstances.Count );
					} else if ( type == typeof(long) ) {
						rowAll[kpiname] = (long)( (long)rowAll[kpiname] / _lstInstances.Count );
					} else if ( type == typeof(double) ) {
						rowAll[kpiname] = (double)( (double)rowAll[kpiname] / _lstInstances.Count );
					} else if ( type == typeof(float) ) {
						rowAll[kpiname] = (float)( (float)rowAll[kpiname] / _lstInstances.Count );
					} else if ( type == typeof(decimal) ) {
						rowAll[kpiname] = (decimal)( (decimal)rowAll[kpiname] / _lstInstances.Count );
					} else {
					}
				}
			}
			dtResultSummary.Rows.Add(rowAll);
			dgvResultsSummery.DataSource = dtResultSummary;
		}
		private void showTrackedDocuments()
		{
			TreeModel model = new TreeModel();
			foreach ( DocumentTrackingValue doc in _trackedDocuments ) {
				model.Root.Nodes.Add(doc);
			}
			tvAdvTrackedDocumentCapabilities.Model = model;
		}
		private NamedBusinessObjectCollection getBusinessObjectsOfOrchestration(int wfID)
		{
			BindingListEx<LogicalActivity> logActs = Global.Data.GetLogicalActivitiesOfWorkflow(wfID);
			NamedBusinessObjectCollection wfObjects = new NamedBusinessObjectCollection();
			foreach ( LogicalActivity logAct in logActs ) {
				if ( logAct.OutputBusinessObject != null ) {
					wfObjects.AddDistinct(
						new NamedBusinessObject(logAct.OutputVariableName, logAct.OutputBusinessObject, logAct));
				}
			}
			return wfObjects;
		}

		#endregion

		#region Event Handlers

		private void btnStartSim_Click(object sender, EventArgs e)
		{
			if ( !btnStartSim.Text.StartsWith("Stop Simulation") ) {
				beginSimulation(true);
			} else {
				endSimulation();
				setButtons(false);
			}
		}

		private void _trackingsvc_CompletedOrTerminated(object sender, SimulationTrackingEventArgs e)
		{
			if ( e.Record != null && e.Record.EventArgs != null )
				addTrackingData(e.Parameters.InstanceId, sender.GetType().Name, "CompletedOrTerminated", e.Record.EventArgs.ToString());
			else
				addTrackingData(e.Parameters.InstanceId, sender.GetType().Name, "CompletedOrTerminated", "");

			_completedCount++;

			this.Invoke(new MethodInvoker(this.showProgress));
		}

		private AutoResetEvent _waitHandle = null;
		private void _trackingsvc_Tracking(object sender, SimulationTrackingEventArgs e)
		{
			ActivityTrackingRecord rA = e.Record as ActivityTrackingRecord;
			WorkflowTrackingRecord rW = e.Record as WorkflowTrackingRecord;
			UserTrackingRecord rU = e.Record as UserTrackingRecord;

			int order = 0;
			DateTime dt = DateTime.Now;
			string type = "", name = "", info = "";
			if ( rA != null ) {
				order = rA.EventOrder;
				dt = rA.EventDateTime;
				type = rA.ActivityType.Name;
				name = rA.QualifiedName;
				info = rA.ExecutionStatus.ToString();
				if ( rbnDocuments.Checked ) {
					if ( rA.Body.Count > 0 ) {
						if ( rA.Body[0].Data == null ) return;
						FieldInfo fi = rA.Body[0].Data.GetType().GetField("_orchestration", BindingFlags.NonPublic | BindingFlags.Instance);
						object obj = fi.GetValue(rA.Body[0].Data);
						Type orchType = obj.GetType();
						MethodInfo clone = orchType.GetMethod("Clone");
						if ( rA.Body.Count > 1 ) {
							LogicalActivity la = Global.Data.RepositoryService.GetItem<LogicalActivity>((int)rA.Body[1].Data);
							if ( rA.ExecutionStatus == ActivityExecutionStatus.Executing ) {
								if ( rA.Body.Count == 2 ) {
									if ( la != null ) {
										#region Simulation variables needed (ILogicalActivity)
										BusinessObject output = la.OutputBusinessObject;
										NamedBusinessObjectCollection input = la.GetSubscribedBusinessObjects();
										if ( output == null ) return;

										NamedBusinessObjectCollection wfObjects = getBusinessObjectsOfOrchestration(_wfController.Workflow.ID);

										wfObjects.AddRangeDistinct(input);
										BindingListEx<object> inputDocuments = new BindingListEx<object>();
										foreach ( NamedBusinessObject item in input ) {
											PropertyInfo prop = orchType.GetProperty(item.Name);
											if ( prop != null ) {
												inputDocuments.Add(prop.GetValue(obj, null));
											} else {
												// object count must match! (or else an exception is thrown)
												inputDocuments.Add(null);
											}
										}
										XmlDocument inputDoc = null;
										if ( la.InputXslt != null ) {
											inputDoc = la.GetMappedInputObject(inputDocuments);
										}

										Verb v = la.Verb;
										Image img = null;
										if ( v == null ) {
										} else {
											if ( la != null &&
												 la.LogicalMethod != null &&
												 la.LogicalMethod.IsAssignedTo == LogicalMethodAssignedTo.MessageQueue ) {
												if ( rA.ActivityType == typeof(OpenComposite.Workflow.LogicalAsyncStartActivity) ) {
													img = Resources.logact_async_start;
												} else {
													img = Resources.logact_async_end;
												}
											} else {
												img = v.Image;
											}
											setDocumentOverviewHeader(v);
											loadDocumentView(input, inputDoc, la.InputBusinessObject, new NamedBusinessObject(la.OutputVariableName, output, la), obj, wfObjects);
											this.Invoke(new MethodInvoker(selectDocumentViewTab));
											_waitHandle.WaitOne();

											SimulationVariable rootVar = outputView.RootNode as SimulationVariable;
											PropertyInfo outProp = orchType.GetProperty(rootVar.VarName);

											outProp.SetValue(obj, outputView.CreateInputObject(rootVar), null);

											fi.SetValue(rA.Body[0].Data, obj);
											object cloned = clone.Invoke(obj, null);
											_trackedDocuments.Add(new DocumentTrackingValue(img, v.Name, cloned, la.ID));
										}
										#endregion
									}
								}
							} else if ( rA.ExecutionStatus == ActivityExecutionStatus.Closed ) {
								object cloned = clone.Invoke(obj, null);
								if ( rA.ActivityType == typeof(OpenComposite.Workflow.NotificationActivity) ) {
									_trackedDocuments.Add(new DocumentTrackingValue(Resources.ico_message.ToBitmap(),
										la.Name, new object[] { cloned, rA.Body[2].Data }, la.ID));
								} else if ( rA.ActivityType == typeof(OpenComposite.Workflow.ExtendedCodeActivity) ) {
									_trackedDocuments.Add(new DocumentTrackingValue(Resources.code,
										rA.QualifiedName, cloned, 0/*la.ID*/));
								} else if ( rA.ActivityType != typeof(OpenComposite.Workflow.LogicalCapabilityActivity) &&
											rA.ActivityType != typeof(OpenComposite.Workflow.LogicalAsyncStartActivity) ) {
									if ( rA.ActivityType == typeof(OpenComposite.Workflow.LogicalAsyncEndActivity) ) {
										_trackedDocuments.Add(new DocumentTrackingValue(Resources.logact_async_start, la.Display, cloned, la.ID));
									} else {
										_trackedDocuments.Add(new DocumentTrackingValue(la.Image, la.Display, cloned, la.ID));
									}
								} else {
								}
								return;
							} else {
							}
						} else {
						}
					}
				}
			} else if ( rW != null ) {
				order = rW.EventOrder;
				dt = rW.EventDateTime;
				type = "Workflow";
				name = "";
				info = rW.TrackingWorkflowEvent.ToString();
			} else if ( rU != null ) {
				order = rU.EventOrder;
				dt = rU.EventDateTime;
				type = rU.ActivityType.Name;
				name = rU.QualifiedName;
				if ( rU.UserData is OpenComposite.Workflow.KPITrackingData ) {
					info = rU.UserData.ToString();
					OpenComposite.Workflow.KPITrackingData data = (OpenComposite.Workflow.KPITrackingData)rU.UserData;
					addKPITrackingDataToResults(e.Parameters.InstanceId, name, data);
				} else
					info = rU.UserDataKey + "= " + rU.UserData.ToString();
			}
			if ( rbnProcess.Checked ) {
				try {
					this.Data.Rows.Add(order, dt, type, name, info, e.Parameters.InstanceId);
				} catch ( Exception ex ) {
					Debug.WriteLine(ex.ToString());
				}
			}
		}

		private void setDocumentOverviewHeader(Verb v)
		{
			this.Invoke(new MethodInvoker(delegate
			{
				txtCapability.Text = v.Name;
				txtDescription.Text = v.Description;
			}));
		}

		#region Workflow
		private void _runtime_WorkflowUnloaded(object sender, WorkflowEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Unloaded", "");
		}

		private void _runtime_WorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Terminated", e.Exception.Message);
		}

		private void _runtime_WorkflowSuspended(object sender, WorkflowSuspendedEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Suspended", e.Error);
		}

		private void _runtime_WorkflowStarted(object sender, WorkflowEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Started", "");
		}

		private void _runtime_WorkflowResumed(object sender, WorkflowEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Resumed", "");
		}

		private void _runtime_WorkflowPersisted(object sender, WorkflowEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Persisted", "");
		}

		private void _runtime_WorkflowLoaded(object sender, WorkflowEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Loaded", "");
		}

		private void _runtime_WorkflowIdled(object sender, WorkflowEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Idled", "");
		}

		private void _runtime_WorkflowCreated(object sender, WorkflowEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Created", "");
		}

		private void _runtime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
		{
			StringBuilder info = new StringBuilder();
			foreach ( KeyValuePair<string, object> keyval in e.OutputParameters ) {
				if ( info.Length > 0 )
					info.Append("; ");
				info.AppendFormat("{0} = {1}", keyval.Key, keyval.Value);
			}
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Completed", info.ToString());
		}

		private void _runtime_WorkflowAborted(object sender, WorkflowEventArgs e)
		{
			addTrackingData(e.WorkflowInstance.InstanceId, "Workflow", "Aborted", "");
		}
		#endregion

		private void tsbtnSimStart_Click(object sender, EventArgs e)
		{
			beginSimulation(false);
		}

		private void tsbtnCompileStart_Click(object sender, EventArgs e)
		{
			beginSimulation(true);
		}
		private void tsbtnSimStop_Click(object sender, EventArgs e)
		{
			endSimulation();
			setButtons(false);
		}

		private void tsbtnViewSimCycles_Click(object sender, EventArgs e)
		{
			dgvSimVars.CommitEdit(DataGridViewDataErrorContexts.Commit);
			calculateSimCycles();
			FormViewSimulationCycles frm = new FormViewSimulationCycles(dtSimCycles);
			frm.ShowDialog();
		}

		private void dgvSimVars_CellValueChanged(object sender, DataGridViewCellEventArgs e)
		{
			if ( e.RowIndex >= 0 && ( e.ColumnIndex == colMinValue.Index ||
									  e.ColumnIndex == colMaxValue.Index ||
									  e.ColumnIndex == colSteps.Index ) ) {
				string value = dgvSimVars[e.ColumnIndex, e.RowIndex].Value.ToString();
				string dataType = dgvSimVars[colDataType.Index, e.RowIndex].Value.ToString();
				if ( !checkValue(ref value, dataType) ) {
					dgvSimVars[e.ColumnIndex, e.RowIndex].Value = "";
				} else {
					dgvSimVars[e.ColumnIndex, e.RowIndex].Value = value;
					//calculateSimCycles();
				}
			}
		}

		private void dgvSimVars_KeyUp(object sender, KeyEventArgs e)
		{
			if ( dgvSimVars.SelectedCells.Count < 1 ) return;
			int row = dgvSimVars.SelectedCells[0].RowIndex;
			int col = dgvSimVars.SelectedCells[0].ColumnIndex;
			if ( e.KeyCode == Keys.Delete ) {
				if ( row >= 0 && ( col == colMinValue.Index ||
										  col == colMaxValue.Index ||
										  col == colSteps.Index ) ) {
					dgvSimVars.SelectedCells[0].Value = "";
				}
			}
		}

		private void bgworkerSimStart_DoWork(object sender, DoWorkEventArgs e)
		{
			bool ok = startWFAsync();
			e.Result = ok;
			if ( !ok ) {
				e.Cancel = true;
			}
			bgworkerSimStart.ReportProgress(7, "Simulation Executing...");
		}
		private void bgworkerSimStart_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			tsprogressSim.Value += 1;

			string str = e.UserState.ToString();
			if ( !string.IsNullOrEmpty(str) )
				tslblStatus.Text = str;

			Application.DoEvents();
		}
		private void bgworkerSimStart_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
			bool ok = false;
			if ( e.Cancelled ) {
				ok = false;
			} else if ( e.Result is bool )
				ok = (bool)e.Result;

			if ( !ok ) {
				this.Cursor = Cursors.Default;
				Application.DoEvents();
				if ( _currentCompileResults != null && _currentCompileResults.Errors.Count > 0 ) {
					StringBuilder errors = new StringBuilder();
					foreach ( CompilerError compilerError in _currentCompileResults.Errors ) {
						string file = Path.GetFileName(compilerError.FileName);
						errors.AppendLine(string.Format("{0}: Line {1}: {2}", file, compilerError.Line, compilerError.ErrorText));
					}

					if ( errors.Length != 0 ) {
						MessageBox.Show(this, errors.ToString(), "Compile Orchestration", MessageBoxButtons.OK, MessageBoxIcon.Error);
					}
				} else {
					MessageBox.Show("Simulation failed.");
				}
				stopWF();
			}
		}

		private void FormWorkflowSimulation_Load(object sender, EventArgs e)
		{
			foreach ( string name in Enum.GetNames(typeof(Distribution)) ) {
				colDistribution.Items.Add(name);
			}
			BindingListEx<KeyPerformanceIndicator> kpis = Global.Data.GetKeyPerformanceIndicatiors();
			cmbKPI.DataSource = kpis;
			KeyPerformanceIndicator kpi = cmbKPI.SelectedValue as KeyPerformanceIndicator;
			cmbUnitOfMeasurement.DataSource = kpi.ExtendedProperties.Units;
			cmbKPI.DisplayMember = "Name";
			cmbKPI.ValueMember = "Name";
			cmbKPI.SelectedIndex = 0;
			this.reportSimResult.RefreshReport();
		}

		private void tscmbCycles_DropDownClosed(object sender, EventArgs e)
		{
			//_customSimCyclesCount = true;
		}

		private void tscmbCycles_KeyDown(object sender, KeyEventArgs e)
		{
			//_customSimCyclesCount = true;
			if ( e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter ) {
				calculateSimCycles();
			}
		}

		private void dgvResults_SelectionChanged(object sender, EventArgs e)
		{
			if ( dgvResults.SelectedCells.Count > 0 &&
				 dgvResults.SelectedCells[0].ColumnIndex > 1 ) {
				showResults(dgvResults.Columns[dgvResults.SelectedCells[0].ColumnIndex].DataPropertyName);
			} else {
				showResults(null);
			}
		}
		private void dgvResults_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
		{
			if ( e.ColumnIndex > 1 ) {
				showResults(dgvResults.Columns[e.ColumnIndex].DataPropertyName);
			}
		}

		private void dgvResultsSummery_SelectionChanged(object sender, EventArgs e)
		{
			if ( dgvResultsSummery.SelectedCells.Count > 0 &&
				 dgvResultsSummery.SelectedCells[0].ColumnIndex > 0 ) {
				showResultsSummary(dgvResultsSummery.Columns[dgvResultsSummery.SelectedCells[0].ColumnIndex].DataPropertyName);
			}
		}
		private void dgvResultsSummery_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
		{
			if ( e.ColumnIndex > 1 ) {
				showResultsSummary(dgvResultsSummery.Columns[e.ColumnIndex].DataPropertyName);
			}
		}


		private void dgvResults_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
		{
		}

		private void dgvSimVars_DataError(object sender, DataGridViewDataErrorEventArgs e)
		{
			if ( e.ColumnIndex == colDistribution.Index ) {
				e.Cancel = true;
				e.ThrowException = true;
			}
		}
		private void dgvSimVars_CellClick(object sender, DataGridViewCellEventArgs e)
		{
			//if ( e.RowIndex == -1 )	// is header
			//    return;

			//string datatype = dgvSimVars.Rows[e.RowIndex].Cells[colDataType.Index].Value as string;
			//if ( e.ColumnIndex == colMinValue.Index ) {
			//    if ( datatype != null ) {
			//        if ( datatype.ToLower().StartsWith("bool") ) {
			//            colMinValue.Items.Clear();
			//            colMinValue.Items.AddRange("True", "False");
			//        } else {
			//            colMinValue.Items.Clear();
			//        }
			//    }
			//} else if ( e.ColumnIndex == colMaxValue.Index ) {
			//    if ( datatype != null ) {
			//        if ( datatype.ToLower().StartsWith("bool") ) {
			//            colMaxValue.Items.Clear();
			//            colMaxValue.Items.AddRange("True", "False");
			//        } else {
			//            colMaxValue.Items.Clear();
			//        }
			//    }
			//}
		}

		private void cmbKPI_SelectedIndexChanged(object sender, EventArgs e)
		{
			string kpinm = cmbKPI.SelectedValue as string;
			if ( !string.IsNullOrEmpty(kpinm) ) {
				cmbUnitOfMeasurement.DataSource = Global.Data.GetKeyPerformanceIndicatior(kpinm).ExtendedProperties.Units;
				//KpiUnit unit = cmbUnitOfMeasurement.SelectedItem as KpiUnit;
				showResults(kpinm);
			}
		}

		private void cmbUnitOfMeasurement_SelectedIndexChanged(object sender, EventArgs e)
		{
			string kpinm = cmbKPI.SelectedValue as string;
			if ( !string.IsNullOrEmpty(kpinm) ) {
				//KpiUnit unit = cmbUnitOfMeasurement.SelectedItem as KpiUnit;
				showResults(kpinm);
			}
		}

		private void rbnProcess_CheckedChanged(object sender, EventArgs e)
		{
			simVarsSplitPanel.Panel1Collapsed = !rbnProcess.Checked;
			simVarsSplitPanel.Panel2Collapsed = rbnProcess.Checked;
			groupBox5.Text = "Set Simulation Variables";
		}

		private void rbnDocuments_CheckedChanged(object sender, EventArgs e)
		{
			simVarsSplitPanel.Panel1Collapsed = rbnDocuments.Checked;
			simVarsSplitPanel.Panel2Collapsed = !rbnDocuments.Checked;
			groupBox5.Text = "Define Orchestration Input Values";
		}

		private void tsbtnContinue_Click(object sender, EventArgs e)
		{
			tsbtnContinue.Enabled = false;
			tsbtnContinue.Visible = false;
			tsbtnSimStart.Visible = true;
			_waitHandle.Set();
		}

		private void tvAdvTrackedDocumentCapabilities_SelectionChanged(object sender, EventArgs e)
		{
			if ( tvAdvTrackedDocumentCapabilities.SelectedNode == null ) return;
			DocumentTrackingValue doc = tvAdvTrackedDocumentCapabilities.SelectedNode.Tag as DocumentTrackingValue;
			// reset old Business Objects 
			boTvTrackedDocuments.Model = null;
			boTvTrackedDocuments.BusinessObject = null;
			boTvTrackedDocuments.InputBusinessObject = null;
			boTvTrackedDocuments.NamedBusinessObject = null;
			boTvTrackedDocuments.OutputBusinesObject = null;
			boTvTrackedDocuments.SubscribedBusinessObjects = null;
			boTvTrackedDocuments.AdditionalBusinessObjects = null;
			if ( boTvTrackedDocuments.Root.Children.Count == 0 ) {
				NamedBusinessObjectCollection bobjects = getBusinessObjectsOfOrchestration(_wfController.Workflow.ID);
				if ( _wfController.Workflow.InputBusinessObject != null ) {
					bobjects.InsertDistinct(0,
						new NamedBusinessObject(_wfController.Workflow.InputBusinessObject.Name,
							_wfController.Workflow.InputBusinessObject));
				}
				if ( _wfController.Workflow.OutputBusinessObject != null ) {
					bobjects.AddDistinct(new NamedBusinessObject(_wfController.Workflow.OutputBusinessObject.Name,
						_wfController.Workflow.OutputBusinessObject));
				}
				boTvTrackedDocuments.WorkflowController = _wfController;
				boTvTrackedDocuments.CompiledAssembly = _currentCompileResults.CompiledAssembly;
				LogicalActivity la = Global.Data.RepositoryService.GetItem<LogicalActivity>(doc.LogicalActivityID);
				if ( la != null ) {
					NamedBusinessObjectCollection subscribed = la.GetSubscribedBusinessObjects();
					if ( subscribed != null ) {
						boTvTrackedDocuments.SubscribedBusinessObjects = subscribed;
						foreach ( NamedBusinessObject item in subscribed ) {
							if ( bobjects.Contains(item) ) {
								bobjects.Remove(item);
							}
						}
					}
					#region Mapped Input Object / Read From Xml
					XmlDocument xmlDoc = null;
					if ( doc.Documents != null ) {
						object obj = null;
						if ( doc.Documents is object[] ) {
							object[] array = doc.Documents as object[];
							if ( array.Length > 0 ) obj = array[0];
						} else {
							obj = doc.Documents;
						}
						xmlDoc = la.GetMappedInputObject(getSubscribedObjects(subscribed, obj));
					}
					boTvTrackedDocuments.InputDocument = xmlDoc;
					#endregion
					boTvTrackedDocuments.InputBusinessObject = la.InputBusinessObject;
					if ( la.HasOutputBusinessObject ) {
						boTvTrackedDocuments.OutputBusinesObject = new NamedBusinessObject(la.OutputVariableName, la.OutputBusinessObject, la);
					} else {
						boTvTrackedDocuments.OutputBusinesObject = null;
					}
					if ( la.OutputBusinessObject != null ) {
						if ( bobjects.Contains(la.OutputBusinessObject) ) {
							bobjects.Remove(la.OutputVariableName);
						}
					}
					boTvTrackedDocuments.AdditionalBusinessObjects = bobjects;

				} else {
					// simple view (no folders)
					boTvTrackedDocuments.SubscribedBusinessObjects = bobjects;
				}
				boTvTrackedDocuments.Load();
			}
			boTvTrackedDocuments.ClearBusinessObjectValues();
			if ( doc.Documents == null ) return;
			if ( doc.Documents is object[] ) {
				object[] array = doc.Documents as object[];
				if ( array[1] is OpenComposite.Workflow.NotifcationData ) {
					OpenComposite.Workflow.NotifcationData data = array[1] as OpenComposite.Workflow.NotifcationData;
					splitContainerDocumentOrText.Panel1Collapsed = false;
					splitContainerDocumentOrText.Panel2Collapsed = true;
					txtRecipient.Text = data.Recipient;
					txtSubject.Text = data.Subject;
					txtBody.Text = data.Message;
					if ( array[0] != null ) {
						splitContainerDocumentOrText.Panel2Collapsed = false;
						boTvTrackedDocuments.ReadObject(array[0], true);
					}
				}
			} else {
				splitContainerDocumentOrText.Panel1Collapsed = true;
				splitContainerDocumentOrText.Panel2Collapsed = false;
				boTvTrackedDocuments.ReadObject(doc.Documents, true);
			}
		}

		void dtSimVars_RowChanging(object sender, System.Data.DataRowChangeEventArgs e)
		{
		}

		#region DragDrop
		private void inputView_ItemDrag(object sender, ItemDragEventArgs e)
		{
			TreeNodeAdv[] nodes = e.Item as TreeNodeAdv[];
			SimulationVariable simVar = nodes[0].Tag as SimulationVariable;
			if ( simVar == null ) return;
			if ( simVar.Field == null ) return;
			this.DoDragDrop(simVar, DragDropEffects.Copy | DragDropEffects.Scroll);
		}

		#region Target
		private void outputView_DragDrop(object sender, DragEventArgs e)
		{
			SimulationVariable simVar = e.Data.GetData(typeof(SimulationVariable)) as SimulationVariable;
			if ( simVar == null || simVar.Field == null ) return;
			NodeControlInfo nci = outputView.GetNodeControlInfoAt(outputView.PointToClient(new Point(e.X, e.Y)));
			if ( nci.Node == null ) return;
			outputView.SelectedNode = nci.Node;
			SimulationVariable target = nci.Node.Tag as SimulationVariable;
			if ( simVar.DataType == target.DataType ) {
				if ( simVar.Nodes.Count > 0 ) {
					copyValues(simVar, target);
					//foreach ( Node child in simVar.Nodes ) {
					//    SimulationVariable sv = child as SimulationVariable;
					//    if ( sv == null || sv.Field == null ) continue;
					//    SimulationVariable tv = null;
					//    if ( target.Nodes.Count == sv.Index ) {
					//        tv = outputView.AddListElementToNode(sv);
					//        foreach ( Node subChild in sv.Nodes ) {
					//            SimulationVariable subSv = subChild as SimulationVariable;
					//            if ( subSv == null || subSv.Field == null ) continue;
					//            SimulationVariable SubTv = target.Nodes[sv.Index] as SimulationVariable;
					//            if ( subTv == null || subTv.Field == null ) continue;
					//            SubTv.StartValue = subSv.StartValue;
					//        }
					//    } else {
					//        tv = target.Nodes[sv.Index] as SimulationVariable;
					//    }
					//    if ( tv == null || tv.Field == null ) continue;
					//    tv.StartValue = sv.StartValue;
					//}
				} else {
					target.StartValue = simVar.StartValue;
				}
			} else {
				string error = string.Format("Data type of {0} ({1}) does not match data type of {2} ({3})",
					simVar.VarName, simVar.DataType, target.VarName, target.DataType);
				MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void copyValues(SimulationVariable sourceNode, SimulationVariable targetNode)
		{
			foreach ( Node child in sourceNode.Nodes ) {
				SimulationVariable sv = child as SimulationVariable;
				if ( sv == null || sv.Field == null ) continue;
				SimulationVariable tv = null;
				if ( sourceNode.DataType.StartsWith("List of") ) {
					if ( targetNode.Nodes.Count == sv.Index ) {
						tv = outputView.AddListElementToNode(targetNode);
					}
					tv = targetNode.Nodes[sv.Index] as SimulationVariable;
					copyValues(sv, tv);
				} else {
					tv = targetNode.Nodes[sv.Index] as SimulationVariable;
					if ( tv == null || tv.Field == null ) continue;
					tv.StartValue = sv.StartValue;
					if ( tv.Nodes.Count > 0 ) {
						copyValues(sv, tv);
					}
				}
			}
		}

		private void outputView_DragOver(object sender, DragEventArgs e)
		{
			SimulationVariable simVar = e.Data.GetData(typeof(SimulationVariable)) as SimulationVariable;
			if ( simVar != null && simVar.Field != null ) {
				e.Effect = e.AllowedEffect;
			}
		}
		#endregion
		#endregion
		#endregion

		#endregion

		public WorkflowController WorkflowController
		{
			get { return this._wfController; }
		}

		private BindingListEx<object> getSubscribedObjects(NamedBusinessObjectCollection subscribedBObjects, object orchestration)
		{
			BindingListEx<object> inputDocuments = new BindingListEx<object>();
			foreach ( NamedBusinessObject item in subscribedBObjects ) {
				PropertyInfo prop = orchestration.GetType().GetProperty(item.Name);
				if ( prop != null ) {
					inputDocuments.Add(prop.GetValue(orchestration, null));
				} else {
					// object count must match! (or else an exception is thrown)
					inputDocuments.Add(null);
				}
			}
			return inputDocuments;
		}

		private bool checkValue(ref string value, string dataType)
		{
			bool valueOk = false;
			NumberFormatInfo numberFormat = NumberFormatInfo.InvariantInfo;
			if ( dataType == "int" ) {
				int result = 0;
				valueOk = int.TryParse(value, NumberStyles.Integer, numberFormat, out result);
			} else if ( dataType == "float" ) {
				float result = 0.0F;
				valueOk = float.TryParse(value.Replace(',', '.'),
					NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat,
					out result);
			} else if ( dataType == "double" ) {
				double result = 0.0;
				valueOk = double.TryParse(value.Replace(',', '.'),
					NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat,
					out result);
			} else if ( dataType == "decimal" ) {
				decimal result = 0.0M;
				valueOk = decimal.TryParse(value.Replace(',', '.'),
					NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat,
					out result);
			} else if ( dataType == "dateTime" ) {
				DateTime result = DateTime.MinValue;
				valueOk = DateTime.TryParse(value, CultureInfo.CurrentCulture.DateTimeFormat, DateTimeStyles.None, out result);
			} else if ( dataType == "string" ) {
				valueOk = true;
			} else if ( dataType == "long" ) {
				long result = 0;
				valueOk = long.TryParse(value, NumberStyles.Integer, numberFormat, out result);
			} else if ( dataType == "bool" ) {
				bool result = false;
				valueOk = bool.TryParse(value, out result);
			} else if ( dataType == "TimeSpan" ) {
				TimeSpan result = TimeSpan.Zero;
				valueOk = TimeSpan.TryParse(value, out result);
			}

			if ( !valueOk ) {
				MessageBox.Show("Value is not in correct format!", "Format error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			}
			return valueOk;
		}

		/// <summary>
		/// Loads the document view.
		/// </summary>
		/// <param name="subscribedObjects">The subscribed documents.</param>
		/// <param name="inputDocument">The input document.</param>
		/// <param name="inputObject">The input object describing the input document.</param>
		/// <param name="outputObject">The output documents.</param>
		/// <param name="obj">The object graph representing the process/orchestration</param>
		/// <param name="additionInputBusinessObjects">The additional input business objects.</param>
		private void loadDocumentView(NamedBusinessObjectCollection subscribedObjects, XmlDocument inputDocument, BusinessObject inputObject, NamedBusinessObject outputObject, object obj, NamedBusinessObjectCollection additionInputBusinessObjects)
		{
			outputView.BusinessObject = outputObject.BusinessObject;
			outputView.NamedBusinessObject = outputObject;
			outputView.CompiledAssembly = _currentCompileResults.CompiledAssembly;
			outputView.WorkflowController = _wfController;
			outputView.Load();
			outputView.ReadObject(obj);

			inputView.SubscribedBusinessObjects = subscribedObjects;
			inputView.AdditionalBusinessObjects = additionInputBusinessObjects;
			inputView.InputDocument = inputDocument;
			inputView.InputBusinessObject = inputObject;
			inputView.CompiledAssembly = _currentCompileResults.CompiledAssembly;
			inputView.WorkflowController = _wfController;
			inputView.Load();
			inputView.ReadObject(obj,
				subscribedObjects.Count > 0 || ( additionInputBusinessObjects != null && additionInputBusinessObjects.Count > 0 ));
		}

		private void selectDocumentViewTab()
		{
			tabControl1.SelectedTab = tabDocumentView;
			tsbtnSimStart.Visible = false;
			tsbtnContinue.Visible = true;
			tsbtnContinue.Enabled = true;
		}
	}

	class DocumentTrackingValue : Node
	{
		//public DocumentTrackingValue(Image image, string name, object data)
		//{
		//    Image = image;
		//    _capabilityName = name;
		//    _documents = data;
		//}

		public DocumentTrackingValue(Image image, string name, object data, int logActId)
		{
			Image = image;
			_capabilityName = name;
			_documents = data;
			_logActID = logActId;
		}

		private string _capabilityName = null;
		private object _documents = null;
		private int _logActID = -1;
		public object Documents
		{
			get { return _documents; }
			set { _documents = value; }
		}
		public string CapabilityName
		{
			get { return _capabilityName; }
			set { _capabilityName = value; }
		}
		public int LogicalActivityID
		{
			get { return _logActID; }
			set { _logActID = value; }
		}

	}

	#region Enum: Distribution
	public enum Distribution
	{
		None = 0,
		Rectangular,
		Normal
		// ...
	}
	#endregion


}
